package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.api.IArticleClient;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.exception.CustomException;
import com.heima.common.tess4j.Tess4jClient;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.util.*;
import java.util.stream.Collectors;


@Service
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {

    @Autowired
    private WmNewsMapper wmNewsMapper;

    @Autowired
    private GreenTextScan greenTextScan;

    @Autowired
    private GreenImageScan greenImageScan;

    @Autowired
    private FileStorageService fileStorageService;

    @Autowired
    private IArticleClient iArticleClient;

    @Autowired
    private WmChannelMapper wmChannelMapper;

    @Autowired
    private WmUserMapper wmUserMapper;

    @Autowired
    private WmSensitiveMapper wmSensitiveMapper;

    @Autowired
    private Tess4jClient tess4jClient;
     /**
     * 自媒体文章审核
     *
     * @param id 自媒体文章id
     */


    @Override
    @Async  //标明当前方法是一个异步方法
    public void autoScanWmNews(Integer id) throws Exception {
        //1. 通过文章id查询当前文章数据
        WmNews wmNews = wmNewsMapper.selectById(id);
        //2. 判断文章是否存在,不存在抛出异常
        if (null == wmNews){
            throw new CustomException(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        //3.完成机器审核判断
            //(1)抽取文章中的文本数据和图片图片数据
        ArrayList<String> images = new ArrayList<>();
        StringBuffer conts = new StringBuffer();
        List<Map> maps = JSON.parseArray(wmNews.getContent(), Map.class);
        for (Map map : maps) {
            if ("text".equals(map.get("type"))){
                String cont = (String) map.get("value");
                conts.append(cont);
            }else if ("image".equals(map.get("type"))){
                String image = (String) map.get("value");
                images.add(image);
            }
        }
        //给文章内容中添加标题
        conts.append(wmNews.getTitle());
        //给图片内容里添加图片内容的数据
        if (StringUtils.isNotEmpty(wmNews.getImages())){
            String[] imgs = wmNews.getImages().split(",");
            images.addAll(Arrays.asList(imgs));
        }

        //检验文本是否包含了自定义的铭感词
        Boolean customTextFlag =  handleSensitiveScan(conts.toString(),wmNews);
        if (!customTextFlag){
            return;
        }

        //审核文本数据
        Boolean textFlag= handleTextScan(conts,wmNews);
        //审核图片数据
        Boolean imageFlag=handleImagesScan(images,wmNews);
        if (!textFlag || !imageFlag){
            return;
        }

        //用Feign来同步数据
        ResponseResult responseResult =saveAppArticle(wmNews);
        if(!responseResult.getCode().equals(200)){
            throw new RuntimeException("WmNewsAutoScanServiceImpl-文章审核，保存app端相关文章数据失败");
        }
        //回填article_id
        wmNews.setArticleId((Long) responseResult.getData());
        updateWmNewStatus(wmNews,(short) 9,"审核成功");


    }

    private Boolean handleSensitiveScan(String conts, WmNews wmNews) {
        boolean flag = true;

        //获取所有的敏感词
        List<WmSensitive> wmSensitives = wmSensitiveMapper.selectList(Wrappers.<WmSensitive>lambdaQuery().select(WmSensitive::getSensitives));
        List<String> sensitiveList = wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());

        //初始化敏感词库
        SensitiveWordUtil.initMap(sensitiveList);

        //查看文章中是否包含敏感词
        Map<String, Integer> map = SensitiveWordUtil.matchWords(conts);
        if(map.size() >0){
            updateWmNewStatus(wmNews,(short) 2,"当前文章中存在违规内容"+map);
            flag = false;
        }

        return flag;
    }


    /**
     * 同步数据
     * @param wmNews
     * @return
     */
    private ResponseResult saveAppArticle(WmNews wmNews) {

        ArticleDto articleDto = new ArticleDto();
        BeanUtils.copyProperties(wmNews,articleDto);
        articleDto.setLayout(wmNews.getType());
        //频道
        WmChannel wmChannel = wmChannelMapper.selectById(wmNews.getChannelId());
        if(wmChannel != null){
            articleDto.setChannelName(wmChannel.getName());
        }

        //作者
        articleDto.setAuthorId(wmNews.getUserId().longValue());
        WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());
        if(wmUser != null){
            articleDto.setAuthorName(wmUser.getName());
        }

        //设置文章id
        if(wmNews.getArticleId() != null){
            articleDto.setId(wmNews.getArticleId());
        }
        articleDto.setCreatedTime(new Date());

        ResponseResult responseResult = iArticleClient.saveArticle(articleDto);
        return responseResult;
    }
    /**
     * 保存app端的文章
     * @param wmNews
     */
    /*public  ResponseResult saveAppArticle(WmNews wmNews) {

        ArticleDtoBuilder articleDtoBuilder = new ArticleDtoBuilder(wmNews, wmChannelMapper, wmUserMapper);
        //使用构造器设计模式 方便以后维护
        //构造器设计模式：他最适合用于构建复杂得对象
        // 1、VO 对象
        // 2、一个系统调用另一个系统得时候， 另一个系统，需要一个对象来操作,而且这个对象本身还挺复杂
        ArticleDto articleDto = articleDtoBuilder.buildBeanCopy()
                .buildAuthor()
                .buildBasic()
                .buildChannel()
                .builder();
        return  iArticleClient.saveArticle(articleDto);
    }*/

    /**
     * 审核图片内容
     * @param images
     * @param wmNews
     * @return
     */
    private Boolean handleImagesScan(ArrayList<String> images, WmNews wmNews) throws Exception {
        //判断图片是否有内容
        if (null == images || images.size()==0){
            return false;
        }
        //给图片去重
        images = (ArrayList<String>) images.stream().distinct().collect(Collectors.toList());
        //从minIo中下载图片数据
        ArrayList<byte[]> imageList = new ArrayList<>(images.size());
        for (String imageUrl : images) {
            byte[] bytes = fileStorageService.downLoadFile(imageUrl);
            //添加图片的识别和自定义铭感词的审核
            ByteArrayInputStream in = new ByteArrayInputStream(bytes);
            BufferedImage image = ImageIO.read(in);
            String text = tess4jClient.doOCR(image);
            Boolean isSensitive = handleSensitiveScan(text, wmNews);
            if (!isSensitive){
                return false;
            }


            imageList.add(bytes);
        }
        Map map = greenImageScan.imageScan(imageList);

        if (null != map){

            if ("block".equals(map.get("suggestion"))){
                //审核不通过,修改文章状态
                String warn ="图片中存在违规内容";
                updateWmNewStatus(wmNews,(short)2,warn);
                return false;
            }else if ("review".equals(map.get("suggestion"))){
                //需要人工审核,修改文章状态\
                String warn ="图片中存在不确定的因素,需要人工审核";
                updateWmNewStatus(wmNews,(short)3,warn);
                return false;
            }
            return true;
        }

        return false;

    }

    /**
     * 审核文章内容
     * @param conts
     * @param wmNews
     * @return
     * @throws Exception
     */
    private Boolean handleTextScan(StringBuffer conts, WmNews wmNews) throws Exception {
        Map map = greenTextScan.greeTextScan(conts.toString());
        if (null != map){

            if ("block".equals(map.get("suggestion"))){
                //审核不通过,修改文章状态
                String warn ="文本中存在违规内容";
                updateWmNewStatus(wmNews,(short)2,warn);
                return false;
            }else if ("review".equals(map.get("suggestion"))){
                //需要人工审核,修改文章状态\
                String warn ="文本中存在不确定的因素,需要人工审核";
                updateWmNewStatus(wmNews,(short)3,warn);
                return false;
            }
            return true;
        }

        return false;
    }

    private void updateWmNewStatus(WmNews wmNews, short i, String warning) {
        wmNews.setStatus(i);
        wmNews.setLabels(warning);
        wmNewsMapper.updateById(wmNews);
    }

}
